/**
 * Fetch请求工具类
 * 基于原生Fetch API的请求封装
 */

/**
 * Fetch请求配置接口
 */
export interface FetchConfig {
  url: string;
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
  headers?: Record<string, string>;
  data?: any;
  params?: Record<string, any>;
  timeout?: number;
  withCredentials?: boolean;
  responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
  onUploadProgress?: (progress: number) => void;
  onDownloadProgress?: (progress: number) => void;
}

/**
 * Fetch响应数据接口
 */
export interface FetchResponse<T = any> {
  data: T;
  status: number;
  statusText: string;
  headers: Record<string, string>;
  config: FetchConfig;
}

/**
 * Fetch错误信息接口
 */
export interface FetchError {
  message: string;
  status?: number;
  statusText?: string;
  data?: any;
  config?: FetchConfig;
}

/**
 * Fetch请求类
 */
export class FetchRequest {
  private config: FetchConfig;

  constructor(config: FetchConfig) {
    this.config = config;
  }

  /**
   * 发送请求
   */
  async send<T = any>(): Promise<FetchResponse<T>> {
    const { url, method = 'GET', headers = {}, data, timeout = 10000 } = this.config;

    // 构建请求配置
    const fetchConfig: RequestInit = {
      method,
      headers: new Headers(headers),
      credentials: this.config.withCredentials ? 'include' : 'same-origin'
    };

    // 添加请求体
    if (data) {
      if (data instanceof FormData) {
        fetchConfig.body = data;
      } else if (typeof data === 'object') {
        fetchConfig.headers.set('Content-Type', 'application/json');
        fetchConfig.body = JSON.stringify(data);
      } else {
        fetchConfig.body = data;
      }
    }

    // 创建超时控制器
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    fetchConfig.signal = controller.signal;

    try {
      const response = await fetch(url, fetchConfig);
      clearTimeout(timeoutId);

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const responseData = await this.parseResponse(response);
      const responseHeaders: Record<string, string> = {};
      response.headers.forEach((value, key) => {
        responseHeaders[key] = value;
      });

      return {
        data: responseData,
        status: response.status,
        statusText: response.statusText,
        headers: responseHeaders,
        config: this.config
      };
    } catch (error) {
      clearTimeout(timeoutId);
      throw error;
    }
  }

  /**
   * 解析响应数据
   */
  private async parseResponse(response: Response): Promise<any> {
    const responseType = this.config.responseType || 'json';

    switch (responseType) {
      case 'json':
        return await response.json();
      case 'text':
        return await response.text();
      case 'blob':
        return await response.blob();
      case 'arraybuffer':
        return await response.arrayBuffer();
      default:
        return await response.text();
    }
  }
}

/**
 * Fetch客户端类
 */
export class FetchClient {
  private baseURL: string;
  private timeout: number;
  private headers: Record<string, string>;
  private withCredentials: boolean;

  constructor(config: {
    baseURL?: string;
    timeout?: number;
    headers?: Record<string, string>;
    withCredentials?: boolean;
  } = {}) {
    this.baseURL = config.baseURL || '';
    this.timeout = config.timeout || 10000;
    this.headers = config.headers || {};
    this.withCredentials = config.withCredentials || false;
  }

  /**
   * 发送请求
   */
  async request<T = any>(config: FetchConfig): Promise<FetchResponse<T>> {
    // 处理URL
    const url = config.url.startsWith('http') ? config.url : this.baseURL + config.url;

    // 合并配置
    const finalConfig: FetchConfig = {
      ...config,
      url,
      timeout: config.timeout || this.timeout,
      headers: { ...this.headers, ...config.headers },
      withCredentials: config.withCredentials ?? this.withCredentials
    };

    const request = new FetchRequest(finalConfig);
    return request.send<T>();
  }

  /**
   * GET请求
   */
  async get<T = any>(url: string, params?: Record<string, any>, config?: Partial<FetchConfig>): Promise<FetchResponse<T>> {
    const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
    return this.request<T>({
      ...config,
      url: url + queryString,
      method: 'GET'
    });
  }

  /**
   * POST请求
   */
  async post<T = any>(url: string, data?: any, config?: Partial<FetchConfig>): Promise<FetchResponse<T>> {
    return this.request<T>({
      ...config,
      url,
      method: 'POST',
      data
    });
  }

  /**
   * PUT请求
   */
  async put<T = any>(url: string, data?: any, config?: Partial<FetchConfig>): Promise<FetchResponse<T>> {
    return this.request<T>({
      ...config,
      url,
      method: 'PUT',
      data
    });
  }

  /**
   * DELETE请求
   */
  async delete<T = any>(url: string, config?: Partial<FetchConfig>): Promise<FetchResponse<T>> {
    return this.request<T>({
      ...config,
      url,
      method: 'DELETE'
    });
  }

  /**
   * PATCH请求
   */
  async patch<T = any>(url: string, data?: any, config?: Partial<FetchConfig>): Promise<FetchResponse<T>> {
    return this.request<T>({
      ...config,
      url,
      method: 'PATCH',
      data
    });
  }
}

/**
 * 创建Fetch客户端
 */
export function createFetchClient(config?: {
  baseURL?: string;
  timeout?: number;
  headers?: Record<string, string>;
  withCredentials?: boolean;
}): FetchClient {
  return new FetchClient(config);
}

/**
 * 快速Fetch请求方法
 */
export const fetch = {
  /**
   * 创建Fetch客户端
   */
  createClient: createFetchClient,
  
  /**
   * 快速GET请求
   */
  get: async <T = any>(url: string, params?: Record<string, any>): Promise<FetchResponse<T>> => {
    const client = createFetchClient();
    return client.get<T>(url, params);
  },
  
  /**
   * 快速POST请求
   */
  post: async <T = any>(url: string, data?: any): Promise<FetchResponse<T>> => {
    const client = createFetchClient();
    return client.post<T>(url, data);
  },
  
  /**
   * 快速PUT请求
   */
  put: async <T = any>(url: string, data?: any): Promise<FetchResponse<T>> => {
    const client = createFetchClient();
    return client.put<T>(url, data);
  },
  
  /**
   * 快速DELETE请求
   */
  delete: async <T = any>(url: string): Promise<FetchResponse<T>> => {
    const client = createFetchClient();
    return client.delete<T>(url);
  }
};
